import * as React from 'react';
import { Raphael, Path } from 'react-raphael';

import { ILine, NodeModel } from '../model/Model';
import { LineType, Point, Range } from '../../reducer/const';
import { COLOR } from './Style';

export interface ILineProps extends ILine {
}

export default class Line extends React.Component<ILineProps, any> {

    protected colorStoke;
    protected strokeWidth;

    constructor(props: ILineProps) {
        super(props);
        const {from, to, type, history} = this.props;
        this.state = Object.assign({ from, to, type }, this.calcStartAndEndPoint(this.props));
        if (history) {
            this.colorStoke = COLOR.stroke2;
        } else {
            this.colorStoke = COLOR.stroke0;
        }
        this.strokeWidth = 2;
    }

    getLinePath = (startPoint: Point, endPoint: Point, size = 10) => {
        const angle = Raphael.angle(startPoint.x, startPoint.y, endPoint.x, endPoint.y); // 得到两点之间的角度
        const a45 = Raphael.rad(angle - 45); // 角度转换成弧度
        const a45m = Raphael.rad(angle + 45);
        const x2a = endPoint.x + Math.cos(a45) * size;
        const y2a = endPoint.y + Math.sin(a45) * size;
        const x2b = endPoint.x + Math.cos(a45m) * size;
        const y2b = endPoint.y + Math.sin(a45m) * size;
        const result = ['M', startPoint.x, startPoint.y, 'L', endPoint.x, endPoint.y, 'L', x2a, y2a, 'M', endPoint.x, endPoint.y, 'L', x2b, y2b];
        return result;
    }

    getBezierPath = (startPoint: Point, endPoint: Point, controlPoints = [0.33, 0, 0.66, 1]) => {
        const [fx, fy, sx, sy] = controlPoints;
        const controlPoint01 = [startPoint.x + fx * (endPoint.x - startPoint.x), startPoint.y + fy * (endPoint.y - startPoint.y)];
        const controlPoint02 = [startPoint.x + sx * (endPoint.x - startPoint.x), startPoint.y + sy * (endPoint.y - startPoint.y)];
        return `M${startPoint.x},${startPoint.y}C${controlPoint01} ${controlPoint02} ${endPoint.x},${endPoint.y}`;
    }

    updateFrom = (nodeData: NodeModel) => {
        const state = this.state;
        state.from = nodeData;
        this.setState(this.calcStartAndEndPoint(state));
    }

    updateTo = (nodeData: NodeModel) => {
        const state = this.state;
        state.to = nodeData;
        this.setState(this.calcStartAndEndPoint(state));
    }

    calcStartAndEndPoint = (param: ILineProps) => {
        let startPoint: Point, endPoint: Point;
        const {from, to} = param;
        const startPoints = this.initRangePoints(from.range);
        const endPoints = this.initRangePoints(to.range);

        const csx = from.range.x + from.range.width / 2; // from x 坐标的中心点
        const rsx = from.range.x + from.range.width; // from x 坐标的最右点
        const csy = from.range.y + from.range.height / 2; // from y 坐标的中心点

        const offsetX = 40;
        const offsetY = 20;

        if (csx + offsetX <= to.range.x) {
            if (rsx + offsetX <= to.range.x) {
                startPoint = startPoints.right;
            } else {
                if (csy + offsetY <= to.range.y) {
                    startPoint = startPoints.top;
                } else if (csy >= to.range.y + to.range.height + offsetY) {
                    startPoint = startPoints.bottom;
                } else {
                    startPoint = startPoints.right;
                }
            }
            endPoint = endPoints.left;
        } else if (csx >= to.range.x + to.range.width + offsetX) {
            if (from.range.x >= to.range.x + to.range.width + offsetX) {
                startPoint = startPoints.left;
            } else {
                if (csy + offsetY <= to.range.y) {
                    startPoint = startPoints.top;
                } else if (csy >= to.range.y + to.range.height + offsetY) {
                    startPoint = startPoints.bottom;
                } else {
                    startPoint = startPoints.left;
                }
            }
            endPoint = endPoints.right;
        } else {
            if (csy <= to.range.y) {
                startPoint = startPoints.bottom;
                endPoint = endPoints.top;
            } else {
                startPoint = startPoints.top;
                endPoint = endPoints.bottom;
            }
        }

        if (startPoint == null || endPoint == null) {
            throw Error(from.range.toString() + to.range.toString());
        }
        return { startPoint, endPoint };
    }

    initRangePoints = (range: Range) => {
        // top right bottom left 
        const points = {
            'top': new Point(range.x + range.width / 2, range.y),
            'right': new Point(range.x + range.width, range.y + range.height / 2),
            'bottom': new Point(range.x + range.width / 2, range.y + range.height),
            'left': new Point(range.x, range.y + range.height / 2)
        };
        return points;
    }

    handlerClick = () => {
        console.log('handlerClick');
    }

    render() {
        const {startPoint, endPoint, type} = this.state;
        const lineAttr = { 'fill': 'none', 'stroke': `${this.colorStoke}`, 'stroke-width': `${this.strokeWidth}` };
        let pathString;
        switch (type) {
            case LineType.Bezier:
                pathString = this.getBezierPath(startPoint, endPoint);
                break;
            case LineType.Poly:
                pathString = this.getLinePath(startPoint, endPoint);
                break;
            case LineType.Line: ;
            default:
                pathString = this.getLinePath(startPoint, endPoint);
        }
        return (<Path d={pathString} attr={lineAttr} onClick={this.handlerClick} />);
    }
};
